package common.toolkit.java.util;

import static common.toolkit.java.constant.EmptyObjectConstant.EMPTY_STRING;
import static common.toolkit.java.constant.RegExpConstant.PATTERN_OF_CONTAINS_IP;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import common.toolkit.java.constant.BaseConstant;
import common.toolkit.java.constant.EmptyObjectConstant;
import common.toolkit.java.exception.NotExpectedFormatedException;
import common.toolkit.java.util.collection.CollectionUtil;

/**
 * Description: String Utils
 * 
 * @author nileader / nileader@gmail.com
 * @Date Feb 10, 2012
 */
public class StringUtil {

	/**
	 * Check String is equals. targetStr compare with compareStrArray, and
	 * return true if equals one or more
	 * 
	 * @param targetStr
	 *            寰呮瘮杈冪殑瀛楃涓�
	 * @param compareStrArray
	 *            瑕佹瘮杈冪殑涓�釜鎴栧涓瓧绗︿覆鏍囧噯
	 * @return
	 */
	public static boolean containsIgnoreCase( final String originalStr, final CharSequence targetStr ) {

		if ( null == originalStr ) {
			return false;
		}

		String originalStrCaps = originalStr.toUpperCase();
		String targetStrCaps = targetStr.toString().toUpperCase();
		return originalStrCaps.contains( targetStrCaps );
	}

	/**
	 * Check if string contains ip,姝ゆ柟娉曚笉鑳藉畬鍏ㄥ垽鏂璱p鏄惁鍚堟硶
	 * 
	 * @return
	 */
	public static boolean containsIp( String originalStr ) {

		if ( StringUtil.isBlank( originalStr ) )
			return false;

		Matcher match = PATTERN_OF_CONTAINS_IP.matcher( originalStr );
		return match.matches();
	}

	/**
	 * Description: Remove {_, -, @, $, #, /, &} in string and make letter after
	 * this uppercase.<br>
	 * e.g. ni_lea-der@gmail./com -> niLeaDerGmail.Com
	 * 
	 * @param @param inputString
	 * @param @param firstCharacterUppercase The first letter is need uppercase.
	 * @return String
	 * @throws
	 */
	public static String convertToCamelCaseString( String inputString, boolean firstCharacterUppercase ) {
		if ( null == inputString ) {
			return null;
		}
		StringBuilder sb = new StringBuilder();

		boolean nextUpperCase = false;
		for ( int i = 0; i < inputString.length(); i++ ) {
			char c = inputString.charAt( i );

			switch ( c ) {
			case '_':
			case '-':
			case '@':
			case '$':
			case '#':
			case ' ':
			case '/':
			case '&':
				if ( sb.length() > 0 ) {
					nextUpperCase = true;
				}
				break;

			default:
				if ( nextUpperCase ) {
					sb.append( Character.toUpperCase( c ) );
					nextUpperCase = false;
				} else {
					sb.append( c );
				}
				break;
			}
		}

		if ( firstCharacterUppercase ) {
			sb.setCharAt( 0, Character.toUpperCase( sb.charAt( 0 ) ) );
		} else {
			sb.setCharAt( 0, Character.toLowerCase( sb.charAt( 0 ) ) );
		}

		return sb.toString();
	}

	/**
	 * Return Default if originalStr is empty.
	 * 
	 * @param originalStr
	 *            寰呯‘璁ゅ�
	 * @param defaultStr
	 *            榛樿鍊�
	 * @return 濡傛灉originalStr涓虹┖锛岄偅涔堝氨杩斿洖defaultStr
	 */
	public static String defaultIfBlank( String originalStr, String defaultStr ) {
		if ( StringUtil.isBlank( originalStr ) ) {
			return defaultStr;
		}
		Collections.emptyList();
		return originalStr;
	}

	/**
	 * Check String is equals Ignore Case. targetStr compare with
	 * compareStrArray, and return true if equals all
	 * 
	 * @param targetStr
	 *            寰呮瘮杈冪殑瀛楃涓�
	 * @param compareStrArray
	 *            瑕佹瘮杈冪殑涓�釜鎴栧涓瓧绗︿覆鏍囧噯
	 * @return true if targetStr same with every string in compareStrArray
	 */
	public static boolean equalsIgnoreCaseAll( String targetStr, String... compareStrArray ) {

		if ( StringUtil.isBlank( targetStr ) || null == compareStrArray || 0 == compareStrArray.length ) {
			return false;
		}
		for ( int i = 0; i < compareStrArray.length; i++ ) {
			if ( !targetStr.equalsIgnoreCase( compareStrArray[i] ) ) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Check String is equals. targetStr compare with compareStrArray, and
	 * return true if equals one or more
	 * 
	 * @param targetStr
	 *            寰呮瘮杈冪殑瀛楃涓�
	 * @param compareStrArray
	 *            瑕佹瘮杈冪殑涓�釜鎴栧涓瓧绗︿覆鏍囧噯
	 * @return true if targetStr same with string in compareStrArray one at
	 *         least
	 */
	public static boolean equalsIgnoreCaseOne( String targetStr, String... compareStrArray ) {

		if ( StringUtil.isBlank( targetStr ) || null == compareStrArray || 0 == compareStrArray.length ) {
			return false;
		}
		for ( int i = 0; i < compareStrArray.length; i++ ) {
			if ( targetStr.equalsIgnoreCase( compareStrArray[i] ) ) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 閫氳繃姝ｅ垯琛ㄨ揪鏂瑰紡锛屾壘鍑轰竴涓瓧绗︿覆涓墍鏈夋寚瀹氱殑瀛愪覆
	 * 
	 * @param @param originalStr 瀛楃涓�
	 * @param @param regex 寰呮煡鎵惧瓙涓茬殑姝ｅ垯琛ㄨ揪寮�
	 * @return List<String> 瀛愪覆闆嗗悎
	 * 
	 *         <pre>
	 * 	瀵�/1.1.1.1:sid=0x2337c7074dofj02e,37775[1](queued=0,recved=6,sent=7,sid=0x2337c7074f1102e,sdlfjle,dsfe鐨勭粨鏋滄槸锛�
	 * [sid=0x2337c7074dofj02e, , sid=0x2337c7074f1102e, ]
	 * </pre>
	 */
	public static List< String > findAllByRegex( String originalStr, String regex ) {

		if ( StringUtil.isBlank( originalStr ) || StringUtil.isBlank( regex ) )
			return null;

		List< String > targetStrList = new ArrayList< String >();
		final Pattern patternOfTargetStr = Pattern.compile( regex, Pattern.CANON_EQ );
		final Matcher matcherOfTargetStr = patternOfTargetStr.matcher( originalStr );
		/** 寮�瑙ｆ瀽 */
		while ( matcherOfTargetStr.find() ) {
			targetStrList.add( StringUtil.trimToEmpty( matcherOfTargetStr.group() ) );
		}
		return targetStrList;
	}

	/**
	 * 閫氳繃姝ｅ垯琛ㄨ揪鏂瑰紡锛屾壘鍑轰竴涓瓧绗︿覆涓涓�釜鎸囧畾鐨勫瓙涓�
	 * 
	 * @param @param originalStr 瀛楃涓�
	 * @param @param regex 寰呮煡鎵惧瓙涓茬殑姝ｅ垯琛ㄨ揪寮�
	 * @return List<String> 瀛愪覆闆嗗悎
	 * 
	 *         <pre>
	 * 	瀵�/1.1.1.1:sid=0x2337c7074dofj02e,37775[1](queued=0,recved=6,sent=7,sid=0x2337c7074f1102e,sdlfjle,dsfe鐨勭粨鏋滄槸锛�
	 * sid=0x2337c7074dofj02e,
	 * </pre>
	 */
	public static String findFirstByRegex( String originalStr, String regex ) {

		if ( StringUtil.isBlank( originalStr ) || StringUtil.isBlank( regex ) )
			return EMPTY_STRING;

		final Pattern patternOfTargetStr = Pattern.compile( regex, Pattern.CANON_EQ );
		final Matcher matcherOfTargetStr = patternOfTargetStr.matcher( originalStr );
		/** 寮�瑙ｆ瀽 */
		if ( matcherOfTargetStr.find() ) {
			return StringUtil.trimToEmpty( matcherOfTargetStr.group() );
		}
		return EMPTY_STRING;
	}

	/**
	 * 鐢熸垚绌虹櫧琛�
	 * 
	 * @param lines
	 *            琛屾暟
	 */
	public static String generateLineBlank( int lines ) {
		StringBuilder sb = new StringBuilder();

		for ( int i = 0; i < lines; i++ ) {
			sb.append( "\n" );
		}

		return sb.toString();
	}

	/**
	 * make first letter lower case for str
	 * 
	 * @return Same letter, but the first letter is lower case.
	 */
	public static String makeFirstLetterLowerCase( String str ) {
		String firstLetter = str.substring( 0, 1 );
		return firstLetter.toLowerCase() + str.substring( 1, str.length() );
	}

	/***
	 * check if orginalStr is null or empty. <br>
	 * If have more than one originalStr, use isBlank(String...
	 * originalStrArray)
	 * 
	 * @param originalStr
	 *            寰呯‘璁ゅ�
	 * @return true or false;
	 */
	public static boolean isBlank( String originalStr ) {
		if ( null == originalStr ) {
			return true;
		}
		if ( originalStr.contains( BaseConstant.WORD_SEPARATOR ) ) {
			return false;
		}
		return trimToEmpty( originalStr ).isEmpty();
	}

	/***
	 * check if orginalStr is null or empty
	 * 
	 * @param String
	 *            ... originalStrArray
	 * @return true if have one blank at least.
	 */
	public static boolean isBlank( String... originalStrArray ) {

		if ( null == originalStrArray || 0 == originalStrArray.length )
			return true;
		for ( int i = 0; i < originalStrArray.length; i++ ) {
			if ( isBlank( originalStrArray[i] ) )
				return true;
		}
		return false;
	}

	/**
	 * check the originalStr is contain the whitespace
	 * 
	 * @param originalStr
	 * @return true if contain whitespace
	 */
	public static boolean isContainWhitespace( String originalStr ) {

		if ( StringUtil.isBlank( originalStr ) ) {
			return true;
		}
		int strLen = originalStr.length();
		for ( int i = 0; i < strLen; i++ ) {
			char ch = originalStr.charAt( i );
			if ( Character.isWhitespace( ch ) ) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 字符串连接，使用指定分隔符
	 * 
	 * @param subStr
	 * @return
	 */
	public static String join( String... subStrs ) {

		if ( null == subStrs || 0 == subStrs.length ) {
			return EMPTY_STRING;
		}
		StringBuilder sb = new StringBuilder();
		for ( String subStr : subStrs ) {
			sb.append( subStr ).append( BaseConstant.WORD_SEPARATOR );
		}
		String sbStr = sb.toString();
		if ( sbStr.endsWith( BaseConstant.WORD_SEPARATOR ) ) {
			sbStr = StringUtil.replaceLast( sbStr, BaseConstant.WORD_SEPARATOR, "" );
		}
		return sbStr;
	}

	/**
	 * Description: Replaces last substring of this string that matches the
	 * given regular expression with the given replacement.<br>
	 * Do not worry about null pointer
	 * 
	 * @param @param regex
	 * @param @param replacement
	 * @return String
	 * @throws
	 */
	public static String replaceAll( String originalStr, String replacement, String regex ) {
		return StringUtil.trimToEmpty( originalStr ).replaceAll( regex, replacement );
	}

	public static String replaceAll( String originalStr, String replacement, String... regexArray ) {

		if ( 0 == regexArray.length )
			return originalStr;

		for ( String regex : regexArray ) {
			originalStr = StringUtil.replaceAll( originalStr, replacement, regex );
		}

		return originalStr;
	}

	/**
	 * Description: Replaces last substring of this string that matches the
	 * given regular expression with the given replacement.
	 * 
	 * @param @param regex
	 * @param @param replacement
	 * @param @return
	 * @return String
	 * @throws
	 */
	public static String replaceLast( String originalStr, String regex, String replacement ) {

		if ( StringUtil.isBlank( originalStr ) )
			return EMPTY_STRING;

		int index = originalStr.lastIndexOf( regex );
		if ( -1 == index )
			return originalStr;

		// 鍏堝瓨鍌ㄨ繖涓猧ndex涔嬪墠鐨勬墍鏈塻tr
		String temp = originalStr.substring( 0, index );
		String temp2 = originalStr.substring( index, originalStr.length() );

		temp2 = temp2.replaceFirst( regex, replacement );

		originalStr = temp + temp2;

		return originalStr;
	}

	/**
	 * 用一个map中的值来替换占位符 ${key}
	 * 
	 * @param originalStr
	 *            a string such as :
	 *            "select * from table where id=${id}, name=${name}, gender=${gender}"
	 */
	public static String replacePlaceholder( String originalStr, Map<String,String> values ) {
		if(CollectionUtil.isBlank( values )){
			return originalStr;
		}
		if ( StringUtil.isBlank( originalStr ) )
			return EMPTY_STRING;
		
		for( String key : values.keySet() ){
			String value = StringUtil.trimToEmpty( values.get( key ) );
			String regex = "\\$\\{" + key + "\\}";
			originalStr = originalStr.replaceAll( regex, value );
		}
		return originalStr;
	}
	
	
	/**
	 * Description: Replaces all {n} placeholder use params
	 * 
	 * @param originalStr
	 *            a string such as :
	 *            "select * from table where id={0}, name={1}, gender={3}"
	 * @param replacementParams
	 *            real params: 1,yinshi.nc,male
	 * @note n start with 0
	 */
	public static String replaceSequenced( String originalStr, Object... replacementParams ) {

		if ( StringUtil.isBlank( originalStr ) )
			return EMPTY_STRING;
		if ( null == replacementParams || 0 == replacementParams.length )
			return originalStr;

		for ( int i = 0; i < replacementParams.length; i++ ) {
			String elementOfParams = replacementParams[i] + EmptyObjectConstant.EMPTY_STRING;
			if ( StringUtil.trimToEmpty( elementOfParams ).equalsIgnoreCase( "null" ) )
				elementOfParams = EmptyObjectConstant.EMPTY_STRING;
			originalStr = originalStr.replace( "{" + i + "}", StringUtil.trimToEmpty( elementOfParams ) );
		}

		return originalStr;
	}

	/**
	 * 璁剧疆鍓嶇紑锛屽鏋滆繖涓瓧绗︿覆宸茬粡鏄繖涓墠缂�簡锛岄偅涔堝氨涓嶄綔浠讳綍鎿嶄綔銆� TODO none test
	 * */
	public static String setPrefix( String originalStr, String prefix ) {
		originalStr = StringUtil.trimToEmpty( originalStr );
		prefix = StringUtil.trimToEmpty( prefix );
		if ( !originalStr.startsWith( prefix ) ) {
			originalStr = prefix + originalStr;
		}
		return originalStr;
	}

	/**
	 * 鍒嗗壊瀛楃涓诧紝濡傛灉涓嶆槸鎸囧畾闀垮害锛屾姏鍑哄紓甯�
	 * 
	 * @param originalStr
	 *            鍘熷瓧绗︿覆
	 * @param regex
	 *            鍒嗗壊绗�
	 * @param fixedLength
	 *            鎸囧畾fixed闀垮害
	 * @return 鍒嗗壊鍚庣殑瀛楃涓叉暟缁�
	 * @throws NotExpectedFormatedException
	 */
	public static String[] splitWithFixedLength( String originalStr, String regex, int fixedLength ) throws NotExpectedFormatedException {

		if ( StringUtil.isBlank( regex ) ) {
			return EmptyObjectConstant.EMPTY_STRING_ARRAY;
		}

		if ( StringUtil.isBlank( originalStr ) ) {
			if ( 0 == fixedLength )
				return EmptyObjectConstant.EMPTY_STRING_ARRAY;
			throw new NotExpectedFormatedException( "鎸囧畾fixedLength涓猴細" + fixedLength + ", 浣嗘槸originalStr涓虹┖" );
		}

		String[] strArray = originalStr.split( regex );
		if ( fixedLength != strArray.length ) {
			throw new NotExpectedFormatedException( "鎸囧畾fixedLength涓猴細" + fixedLength + ", 浣嗘槸originalStr涓�" + originalStr );
		}
		return strArray;
	}

	/**
	 * 鍒嗗壊瀛楃涓诧紝濡傛灉灏忎簬鎸囧畾闀垮害锛�=leastLength ok锛夛紝鎶涘嚭寮傚父
	 * 
	 * @param originalStr
	 *            鍘熷瓧绗︿覆
	 * @param regex
	 *            鍒嗗壊绗�
	 * @param leastLength
	 *            鎸囧畾鐨勬渶灏弆east闀垮害
	 * @return 鍒嗗壊鍚庣殑瀛楃涓叉暟缁�
	 * @throws NotExpectedFormatedException
	 */
	public static String[] splitWithLeastLength( String originalStr, String regex, int leastLength ) throws NotExpectedFormatedException {
		if ( StringUtil.isBlank( regex ) ) {
			return EmptyObjectConstant.EMPTY_STRING_ARRAY;
		}

		if ( StringUtil.isBlank( originalStr ) ) {
			if ( 0 == leastLength )
				return EmptyObjectConstant.EMPTY_STRING_ARRAY;
			throw new NotExpectedFormatedException( "鎸囧畾leastLength涓猴細" + leastLength + ", 浣嗘槸originalStr涓虹┖" );
		}

		String[] strArray = originalStr.split( regex );
		if ( leastLength > strArray.length ) {
			throw new NotExpectedFormatedException( "鎸囧畾leastLength涓猴細" + leastLength + ", 浣嗘槸originalStr涓�" + originalStr );
		}
		return strArray;
	}

	/**
	 * 鍒嗗壊瀛楃涓诧紝濡傛灉澶т簬鎸囧畾闀垮害锛�=leastLength ok锛夛紝鎶涘嚭寮傚父
	 * 
	 * @param originalStr
	 *            鍘熷瓧绗︿覆
	 * @param regex
	 *            鍒嗗壊绗�
	 * @param maxLength
	 *            鎸囧畾鐨勬渶澶ax闀垮害
	 * @return 鍒嗗壊鍚庣殑瀛楃涓叉暟缁�
	 * @throws NotExpectedFormatedException
	 */
	public static String[] splitWithMaxLength( String originalStr, String regex, int maxLength ) throws NotExpectedFormatedException {
		if ( StringUtil.isBlank( regex ) ) {
			return EmptyObjectConstant.EMPTY_STRING_ARRAY;
		}

		if ( StringUtil.isBlank( originalStr ) ) {
			return EmptyObjectConstant.EMPTY_STRING_ARRAY;
		}

		String[] strArray = originalStr.split( regex );
		if ( maxLength < strArray.length ) {
			throw new NotExpectedFormatedException( "鎸囧畾maxLength涓猴細" + maxLength + ", 浣嗘槸originalStr涓�" + originalStr );
		}
		return strArray;
	}

	/**
	 * 鍒ゆ柇瀛楃涓叉槸鍚﹁秴杩囨寚瀹氶暱搴︼紝濡備綍瓒呰繃锛屾坊鍔犳寚瀹氬悗缂�
	 * 
	 * @param originalStr
	 *            "閾舵椂鐨�
	 * @param maxLength
	 *            2
	 * @param suffix
	 *            ...
	 * @return "閾舵椂..."
	 */
	public static String subStringIfTooLong( String originalStr, int maxLength, String suffix ) {
		if ( StringUtil.isBlank( originalStr ) )
			return EmptyObjectConstant.EMPTY_STRING;
		if ( maxLength < 0 )
			maxLength = 0;
		if ( originalStr.length() > maxLength )
			return originalStr.substring( 0, maxLength ) + StringUtil.trimToEmpty( suffix );
		return originalStr;
	}

	/**
	 * toString()鏂规硶<br>
	 * Note:涓嶄細鍑虹幇npe锛屼笉浼氳繑鍥瀗ull
	 * 
	 * @param t
	 * @return
	 */
	public static < T > String toString( T t ) {
		if ( ObjectUtil.isBlank( t ) )
			return EmptyObjectConstant.EMPTY_STRING;
		return t.toString();
	}

	/**
	 * Returns a copy of the string, with leading and trailing whitespace
	 * omitted. Don't worry the NullPointerException. Will never return Null.
	 * 
	 * @param originalStr
	 * @return "" or String without empty str.
	 */
	public static String trimToEmpty( String originalStr ) {
		if ( null == originalStr || originalStr.isEmpty() )
			return EMPTY_STRING;
		if ( originalStr.equals( BaseConstant.WORD_SEPARATOR ) )
			return originalStr;
		return originalStr.trim();
	}

	/**
	 * URL编码
	 * 
	 * @param s
	 *            String to be translated.
	 * @param enc
	 *            The name of a supported character encoding.
	 * @return
	 */
	public static String urlEncode( String s, String enc ) {
		if ( StringUtil.isBlank( s ) )
			return StringUtil.trimToEmpty( s );
		try {
			return java.net.URLEncoder.encode( trimToEmpty( s ), enc );
		} catch ( UnsupportedEncodingException e ) {
			return s;
		}
	}

	/**
	 * URL编码,使用UTF-8编码
	 * 
	 * @param s
	 *            String to be translated.
	 * @param enc
	 *            The name of a supported character encoding.
	 * @return
	 */
	public static String urlEncode( String s ) {
		if ( StringUtil.isBlank( s ) )
			return StringUtil.trimToEmpty( s );
		return urlEncode( trimToEmpty( s ), "UTF-8" );
	}

}
